#include "RequirementProxyModel.h"


#include <ItemModel.h>
#include <ItemReference.h>



#include <QDebug>



RequirementProxyModel::RequirementProxyModel(QObject *parent) :
    ReferenceProxyModel(parent)
{
}



int RequirementProxyModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return (RequirementProxyModel::Field_LAST - ReferenceProxyModel::Field_FIRST + 1);
}



QVariant RequirementProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
    QModelIndex idSource = mapToSource(proxyIndex);
    if (!idSource.isValid()) return QVariant();

    if (proxyIndex.column() != ValueField)
    {
        QModelIndex categorySource = idSource.sibling(idSource.row(), AbstractItem::CategoryData);
        if (!categorySource.isValid()) return QVariant();
        if (categorySource.data(Qt::EditRole).toInt() != ItemCategory_Item)
        {
            if (role == Qt::CheckStateRole) return QVariant();
        }

        return ReferenceProxyModel::data(proxyIndex, role);
    }

    if (!m_sourceTarget.isValid()) return QVariant();
    if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();

    QModelIndex refIndex = mapToSourceReference(proxyIndex.sibling(proxyIndex.row(), NameField));
    if (!refIndex.isValid()) return QVariant();

    QModelIndex refValue = refIndex.sibling(refIndex.row(), Item::ValueData);
    if (!refValue.isValid()) return QVariant();

    return refValue.data(Qt::EditRole);

}



bool RequirementProxyModel::setData(const QModelIndex &proxyIndex, const QVariant &value, int role)
{
    if (!m_sourceTarget.isValid() || !proxyIndex.isValid()) return false;

    if (proxyIndex.column() == NameField)
    {
        if (role != Qt::CheckStateRole) return false;
        if (proxyIndex.data(Qt::CheckStateRole).toBool())
        {
            removeReference(proxyIndex);
            return true;
        }

        return createReference(proxyIndex, ItemReference::RequirementRef).isValid();
    }

    if (role != Qt::EditRole) return false;

    QModelIndex sourceRef = mapToSourceReference(proxyIndex.sibling(proxyIndex.row(), NameField));
    if (!sourceRef.isValid()) return false;

    QModelIndex sourceValue = sourceRef.sibling(sourceRef.row(), Item::ValueData);
    if (!sourceValue.isValid()) return false;

    ItemModel* model = itemModel();
    if (!model) return false;

    emit layoutAboutToBeChanged();
    bool ret = model->setData(sourceValue, value, Qt::EditRole);
    emit layoutChanged();
    return ret;
}



QVariant RequirementProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(orientation);
    if (role != Qt::DisplayRole) return QVariant();

    switch (section)
    {
    case NameField:     return tr("Requirement");
    case ValueField:    return tr("Value");
    }

    return QVariant();
}



Qt::ItemFlags RequirementProxyModel::flags(const QModelIndex &index) const
{
    //qDebug() << Q_FUNC_INFO;
    //qDebug() << "source index check";
    QModelIndex sourceIndex = mapToSource(index);
    if (!sourceIndex.isValid()) return Qt::ItemIsEnabled;

    //qDebug() << "source category check";
    QModelIndex categorySource = sourceIndex.sibling(sourceIndex.row(), AbstractItem::CategoryData);
    if (!categorySource.isValid()) return Qt::ItemIsEnabled;

    //qDebug() << "categrory data check" << categorySource.data(Qt::EditRole);
    if (categorySource.data(Qt::EditRole).toInt() != ItemCategory_Item) return Qt::ItemIsEnabled;

    //qDebug("field switch");
    switch (index.column())
    {
    case NameField:
        if (!m_sourceTarget.isValid()) return Qt::NoItemFlags;
        return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;

    case ValueField:
        if (!m_sourceTarget.isValid() || !mapToSourceReference(index.sibling(index.row(), NameField)).isValid()) return Qt::NoItemFlags;
        return Qt::ItemIsEnabled | Qt::ItemIsEditable;
    }

    //qDebug() << "field switch failed";
    return Qt::ItemIsEnabled;
}



void RequirementProxyModel::remap()
{
    ItemModel* model = itemModel();
    if (!model) return;

    QModelIndex groupName = model->index(0,AbstractItem::NameData, QModelIndex());
    while (groupName.isValid())
    {
        QModelIndex groupId = groupName.sibling(groupName.row(), AbstractItem::IdData);
        if (!groupId.isValid())
        {
            groupName = groupName.sibling(groupName.row()+1, groupName.column());
            continue;
        }

        //qDebug() << groupId.data(Qt::EditRole);

        mapIndex(NameField, groupName);
        mapIndex(ValueField, groupId);

        QModelIndex itemName = groupName.child(0, AbstractItem::NameData);
        while (itemName.isValid())
        {
            QModelIndex itemId = itemName.sibling(itemName.row(), AbstractItem::IdData);
            if (itemId.isValid())
            {
                mapIndex(NameField, itemName);
                mapIndex(ValueField, itemId);
            }

            itemName = itemName.sibling(itemName.row()+1, itemName.column());
        }

        groupName = groupName.sibling(groupName.row()+1, groupName.column());
    }

}



void RequirementProxyModel::mapIndex(const int& field, const QModelIndex& sourceIndex)
{
    QModelIndex categorySource = sourceIndex.sibling(sourceIndex.row(), AbstractItem::CategoryData);
    if (!categorySource.isValid()) return;

    switch (categorySource.data(Qt::EditRole).toInt())
    {
    case ItemCategory_Group:
        addMapping(sourceIndex, createIndex(sourceIndex.row(), field, sourceIndex.internalPointer()));
        return;

    case ItemCategory_Item:
        break;

    default:
        return;
    }

    QModelIndex parentSource = sourceIndex.parent();
    if (!parentSource.isValid()) return;

    QModelIndex parentNameSource = parentSource.sibling(parentSource.row(), AbstractItem::NameData);
    ProxyIndex parentNameProxy = mapFromSource(parentNameSource);
    if (!parentNameProxy.isValid()) return;

    addChildMapping(parentNameProxy, sourceIndex, createIndex(sourceIndex.row(), field, sourceIndex.internalPointer()));
}


